//
//  ZXRefreshControl.swift
//  loveBee
//
//  Created by zhangxing on 2017/8/17.
//  Copyright © 2017年 zhangXing. All rights reserved.
//

import UIKit

//定义枚举
enum ZXRefreshControlType {
    
    //下拉刷新状态
    case normal
    
    //松手就刷新状态
    case pulling
    
    //正在刷新状态
    case refreshing
}

//定义下拉刷新控件的高度,便于设置frame
let refreshControlHeight = 64

class ZXRefreshControl: UIControl {
    
    //懒加载控件
    //图片1
    lazy var iconImageView1: UIImageView = UIImageView.init(image: #imageLiteral(resourceName: "v2_pullRefresh1"))
    
    //图片2
    lazy var iconImageView2: UIImageView = UIImageView.init(image: #imageLiteral(resourceName: "v2_pullRefresh2"))
    
    
    //标题
    lazy var titleLabel: UILabel = {
        
        let titleLabel = UILabel(fontSize: 14, textColor: UIColor.darkGray)
        
        titleLabel.text = "下拉刷新"
        
        return titleLabel
        
    }()
    
    
    //懒加载定时器
    lazy var timer: Timer = {
        
        let timer = Timer.init(fireAt: Date.init(timeIntervalSinceNow: 0.5), interval: 0.5, target: self, selector: #selector(timeOut), userInfo: nil, repeats: true)
        
        RunLoop.current.add(timer, forMode: .commonModes)
        
        return timer
        
    }()
    
    //标识定时器是否开启(默认没开启)
    var isTimerOpen: Bool = false
    
    //定义一个父视图scrollView,用来记录这个下拉刷新的控件所添加到的父视图上
    var currentScrollView: UIScrollView?
    
    
    //为view的状态枚举赋值,不能使用可选类型(给他一个默认值)
    var refreshControlType: ZXRefreshControlType = .normal {
        
        didSet {
            
            switch refreshControlType {
            case .normal:
                //如果是正常状态,改变文字内容
                titleLabel.text = "下拉刷新"
                
                UIView.animate(withDuration: 0.25, animations: { 
                    //如果之前是刷新状态,就将控件的内边距恢复,如果是pulling状态就不需要恢复内边距了,我们在refreshing状态执行动画结束后就恢复到.normal状态,这里有个oldValue值得注意
                    if oldValue == .refreshing {
                        
                        self.currentScrollView?.contentInset.top -= CGFloat(refreshControlHeight)
                    }
                })
                
            case .pulling:
                //如果是下拉状态,改变文字内容
                titleLabel.text = "放手刷新"
                
            case .refreshing:
                //如果是刷新状态,改变文字内容
                titleLabel.text = "正在刷新中..."
                
                //如果正在刷新中,就动画的修改当前scrollView的内边距,怎样获取scrollView这个父视图,需要使用willMovetoSuperView这个方法
                
                UIView.animate(withDuration: 0.25, animations: {
                    self.currentScrollView?.contentInset.top += CGFloat(refreshControlHeight)
                    
                }, completion: { (_) in
                    //发送事件值改变事件,因为下拉刷新后我们需要结束动画,恢复到正常状态normal
                    self.sendActions(for: .valueChanged)
                })
            
            }
            
        }
        
        
    }
    

    //这是一个自定义控件必须要调用的方法
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        setupUI()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    //  MARK: --   搭建UI
    private func setupUI() {
        
        //添加控件
        //添加iconImageView1
        addSubview(iconImageView1)
        addSubview(iconImageView2)
        addSubview(titleLabel)
        
        
        
        //先将图片2影藏
        //在初始化的时候,就是你影藏它就开启,你开启他就影藏
        iconImageView2.isHidden = iconImageView1.isHidden
        iconImageView1.isHidden = !(iconImageView1.isHidden)
        
       
        //添加约束(因为我们是要封装,所以不可以使用mapkit,需要使用系统的布局方法,这样别人拖进去就可以使用)
        //1.    在使用系统的约束方法之前,首先需要取消自动约束布局
        iconImageView1.translatesAutoresizingMaskIntoConstraints = false
        iconImageView2.translatesAutoresizingMaskIntoConstraints = false
        titleLabel.translatesAutoresizingMaskIntoConstraints = false
        
        
        //2.    使用addConstraint添加约束
        //2.1   让iconImageView1的中心就等于control的中心centerY
        addConstraint(NSLayoutConstraint(item: iconImageView1, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1, constant: 0))
        
        
        //设置iconImageView1的中心x等于control的中心x
        addConstraint(NSLayoutConstraint(item: iconImageView1, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1, constant: -35))
        
        
        //2.2   iconImageView2的中心Y就等于iconImageView1
        addConstraint(NSLayoutConstraint(item: iconImageView2, attribute: .centerY, relatedBy: .equal, toItem: iconImageView1, attribute: .centerY, multiplier: 1, constant: 0))
        
        
        //iconImageView2的中心X就等于iconImageView1
        addConstraint(NSLayoutConstraint(item: iconImageView2, attribute: .centerX, relatedBy: .equal, toItem: iconImageView1, attribute: .centerX, multiplier: 1, constant: 0))
        
        
        //2.3   titleLabel的centerY等于iconImageView1的centerY
        addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .centerY, relatedBy: .equal, toItem: iconImageView1, attribute: .centerY, multiplier: 1, constant: 0))
        
        
        //titleLabel的leading等于iconImageView1的trailing
        addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .leading, relatedBy: .equal, toItem: iconImageView1, attribute: .trailing, multiplier: 1, constant: 0))
        
        
        //设置下拉刷新的占位图的位置
        frame = CGRect(x: 0, y: -refreshControlHeight, width: Int(KWidth), height: refreshControlHeight)
        
        
//        backgroundColor = UIColor.brown
        
        
    }
    
    
    //  MARK: --   视图将要添加到父视图上时,调用这个方法是因为这个方法调用时是一定有父视图的
    override func willMove(toSuperview newSuperview: UIView?) {
        //首先判断移动到的父视图是不是scrollView类型的
        guard let scrollView = newSuperview as? UIScrollView else {
            //如果不能强转成UIscrollView,就直接返回
            return
        }
        
        //如果可以强转成scrollView,就记录下这个父视图,因为我们需要设置它在不同下拉状态时的top距离顶部的距离contentInset
        currentScrollView = scrollView
        
        //KVO监听父视图contentOffset
        scrollView.addObserver(self, forKeyPath: "contentOffset", options: .new, context: nil)
        
        
    }
    
    //  MARK: --   实现KVO的监听方法
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        
        //如果下拉的y值小于0,并且当前定时器是关闭着的,就开启定时器
        if (currentScrollView?.contentOffset.y)! < CGFloat(0) && isTimerOpen == false {
            
            timer.fireDate = Date.init(timeIntervalSinceNow: 0.5)
            
            
            //标记定时器开始
            isTimerOpen = true
        }
        else if isTimerOpen == true && (currentScrollView?.contentOffset.y)! > CGFloat(0) {
            
            //关闭定时器
            timer.fireDate = Date.distantFuture
            
            //标记定时器关闭
            isTimerOpen = false
        }
        
        //计算最大更改的y值.要加上自身的高度和父视图的高度
        let contentOffsetMaxY = -((currentScrollView?.contentInset.top)! + CGFloat(refreshControlHeight))
        
        //判断是否在拖拽
        if (currentScrollView?.isDragging)! {
            
            
            //拖拽
            //偏移量小于设定最大的值(-155 < -154==contentOffsetMaxY),并且之前是默认状态
            if (currentScrollView?.contentOffset.y)! < contentOffsetMaxY && refreshControlType == .normal {
                
                //如果之前是默认状态,并且拖拽的力度超过了这个限度,就修改状态为.pulling
                refreshControlType = .pulling
            }
            else if (currentScrollView?.contentOffset.y)! > contentOffsetMaxY && refreshControlType == .pulling {
                //如果还没有拉到位,并且当前的下拉状态为.pulling,我们就把当前状态修改为normal默认状态
                refreshControlType = .normal
            }
            
        }
        else {
            
            //没有拖拽,没有拖拽的时候在释放刷新就需要刷新数据
            //如果我们没有托到位,那么我们一放手就不需要去刷新数据,如果我们托到位,我们就需要去修改下拉的状态为refreshing
            if refreshControlType == .pulling {
                refreshControlType = .refreshing
            }
        }
        
        
    }
    
    
    //  MARK: --   设置结束刷新方法,将下拉刷新的控件设置为normal
    func endRefreshing() {
        
        //修改状态
        refreshControlType = .normal
    }
    
    //  MARK: --   定时器时间到执行的方法
    @objc private func timeOut() {
        
        //图片动画
        //上次iconImageView1影藏,这次就要iconImageView2影藏
        iconImageView2.isHidden = iconImageView1.isHidden
        
        //iconImageView1的影藏状态正好和上次的相反
        iconImageView1.isHidden = !(iconImageView1.isHidden)
        
    }
    
    //  MARK: --   销毁时调动,让定时器无效
    deinit {
        //定时器无效化
        timer.invalidate()
    }
    
    
    
}
